package cn.caplike.demo.nio._2017;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

/**
 * 简介：Selector Server
 *
 * @author 李珂 2017年11月23日 上午11:27:37
 */
public class SelectorTestServer {
    private Selector selector = null; // 用于检测所有Channel状态的Selector

    public static void main(String[] args) throws IOException {
        new SelectorTestServer().init();
    }

    public void init() throws IOException {
        selector = Selector.open();
        /* 通过open方法来打开一个未绑定的ServerSocketChannel实例 */
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 30000);

        /* 将该ServerSocketChannel绑定到指定ip地址 */
        serverChannel.socket().bind(isa);
        serverChannel.configureBlocking(false);

        /* 将server注册到指定Selector对象 */
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (selector.select() > 0) {

            /* 依次处理selector上的每个以选择的SelectionKey */
            Set<SelectionKey> set = selector.selectedKeys();
            Iterator<SelectionKey> it = set.iterator();
            while (it.hasNext()) {
                SelectionKey sk = it.next();
                it.remove();

                /* 如果sk对应的通道包含客户端的连接请求 */
                if (sk.isAcceptable()) {
                    SocketChannel sc = serverChannel.accept();// 调用accept方法接受连接，产生服务器端对应的SocketChannel
                    sc.configureBlocking(false);// 设置采用非阻塞模式
                    sc.register(selector, SelectionKey.OP_READ);// 将该SocketChannel也注册到selector
                }

                /* 如果sk对应的通道有数据需要读取 */
                if (sk.isReadable()) {
                    SocketChannel sc = (SocketChannel) sk.channel(); // 获取该SelectionKey对应的Channel，该Channel中有可读的数据
                    ByteBuffer buff = ByteBuffer.allocate(1024);
                    String content = "";

                    /* 读数据 */
                    try {
                        while (sc.read(buff) > 0) {
                            buff.flip();
                            content += StandardCharsets.UTF_8.decode(buff);
                        }
                        System.out.println("Msg from client: " + content);// 打印从该sk对应的Channel里读取到的数据
                    } catch (IOException ex) {
                        /*
                         * 如果捕捉到该sk对应的Channel出现了异常，即表明该Channel
                         * 对应的Client出现了问题，所以从Selector中取消sk的注册
                         */
                        sk.cancel();// 从Selector中删除指定的SelectionKey
                        if (sk.channel() != null) {
                            sk.channel().close();
                        }
                    }
                    /* 如果content的长度大于0，即msg不为空 */
                    if (content.length() > 0) {
                        for (SelectionKey key : selector.keys()) {
                            Channel targetChannel = key.channel();
                            if (targetChannel instanceof SocketChannel) {
                                /* 将读到的内容写入该Channel中 */
                                SocketChannel dest = (SocketChannel) targetChannel;
                                dest.write(StandardCharsets.UTF_8.encode(content));
                            }
                        }
                    }
                }
            }
        }
    }

}
